import os
from datetime import datetime

from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.http import HttpResponse
from django.shortcuts import render, redirect

# Create your views here.
# django会把用户的请求信息封装成对象，作为参数传进来
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views import View

from django_study.settings import MEDIA_ROOT
from .form import ArticleForms
from .models import *


def test(request, *args, **kwargs):
    # print(kwargs)
    # info = kwagrs.get("in")
    # print(request)
    # print("test")
    # 返回一个相应对象 返回给用户的数据
    user = User.objects.get(username='adam')
    # 校验密码 check_password参数跟数据库保存的字符是否一致
    # 如果一致的话返回True 如果不一致的话则返回False
    print(user.check_password('zxd3321'))
    return HttpResponse("<h1 style = 'color:red'> hello,django</h1>")


def tv(request, **kwargs):
    return HttpResponse("电视机")


# 用户已经登录
# user={
#     "name": 'rose',
#     "sex": '女'
# }

# 用户的值为None 保存用户未登录状态
# user=None

def nav(request, **kwargs):
    # 定义字典来模拟数据

    #     得到文章的分类：data.get(键)
    #     将分类用变量表示 得到地址栏传递过来的分类 也叫地址栏转换器
    classes = kwargs.get("classes")  # 保存的是转换器参数(从路由)接收到的字符数据
    print(classes)
    # username = request.session.get('username')
    username = request.user.username
    # username =request.session['username']
    # 得到字典中的文章数据

    # 值为空 False 取反为True
    # if not res:
    #     print(reverse('not_find'))
    # return redirect('/demo/404/')
    # return redirect('not_find')
    # return HttpResponse(f"文章数据{classes}分类下的{res}")
    # 渲染模板页面
    # return HttpResponse(render(request,'demo/nav.html'))

    # if classes not in list(data.keys()):
    #     return redirect('not_find')
    # 得到字典中的文章数据 对应分类下的文章数据 字典类型
    # res = data.get(classes)

    # 得到模型类里面的分类对象
    try:
        # 如果获取不到该分类对象就会报错，即数据库里没有这个分类
        res = Classes.objects.get(name=classes)
    except Classes.DoesNotExist:
        # 如果报错就跳转到404页面
        return redirect('not_find')

    return HttpResponse(render(request, 'demo/nav.html',
                               context={
                                   # "articles": res,
                                   # 获取该分类下的所有文章
                                   "articles": res.article_set.all(),
                                   # 当前路由访问的分类名 一个
                                   "now_cls": classes,
                                   # 数据里面所有的分类名 多个
                                   # "classes": data.keys(),
                                   "classes": Classes.objects.all(),
                                   "str1": "hello django",
                                   # "num": 100
                                   "user": username,
                               }))


def not_find(request, **kwargs):
    return HttpResponse("该页面不存在！")


def index(request, **kwargs):
    # django会自动获取请求中的cookie 然后到数据库中的session匹配
    # 可以通过字典【request.session】的键’username‘来获取值
    # username = request.session.get('username')
    username = request.user.username
    print(username)
    # username = request.session['username']
    return HttpResponse(render(request, "demo/index.html", context={
        # "classes": data.keys(),
        # 得到模型类的所有分类对象
        "classes": Classes.objects.all(),
        # "user": User.objects.get(username="Lisa"),
        "user": username,
    }))


def classes(request, **kwargs):
    # 实例化一个对象 并且传入字段
    # 第一种方式
    # classes1 = Classes(name="Python")
    # classes1.save() #保存
    # 第二种方式
    # classes2 = Classes()
    # classes2.name = "java"
    # classes2.save()
    # 第三种方式
    # Classes.objects.create(name="deepseek")
    # 第四种方式
    # Classes.objects.get_or_create(name="html")

    # Classes.objects.filter(name="Python").delete()

    return HttpResponse("数据更新成功")


def tab_info(request, **kwargs):
    # 一对一表数据添加
    # 创建一个用户对象 密码是铭文保存
    # user = User(username="Rose")
    # 密码进行加密操作
    # user.set_password('qwe123')
    # user.save() # 保存加密后的密码
    # 创建一个用户详情对象
    # 如果上面已有用户对象则直接关联用户对象
    # 如果没有对应的关联用户对象 可以通过用户id指定关联的用户对象
    # UserDetail.objects.create(age=19,sex=0,user_id=2)
    # 一对一查询
    # 获取用户Lisa的年龄
    # 先获取用户对象
    # user = User.objects.get(username="Lisa")
    # print(user.userdetail.age)
    # # 获取用户id为2的用户名字
    # userdetail = UserDetail.objects.get(user_id=2)
    # print(userdetail.user.username)

    # 一对多表数据添加
    # 创建一个分类对象
    # classes = Classes.objects.create(name="test")
    # 创建一个文章对象
    # article = Article(title="test01",desc="test-desc01",content="test-content01",cover="https://dimg04.c-ctrip.com/images/1mc3n12000hjg8ej78807_R_600_400_R5_D.jpg",user_id=1,classes_id=33)
    # article.save()

    # 一对多表数据查询
    # 得到test分类下的所有文章
    # 第一步 得到test的fenlei
    # classes = Classes.objects.get(name="test")
    # print(classes.article_set.all())
    # print(classes.article_set.get(title="test"))
    # print(classes.article_set.get(title="test").content)

    # 一对多管理器表数据添加
    # classes = Classes.objects.get(name='Python')
    # 通过管理器来添加
    # classes.article_set.create(title="test03",desc="test-desc03",content="test-content03",cover="https://dimg04.c-ctrip.com/images/1mc3n12000hjg8ej78807_R_600_400_R5_D.jpg",user_id=1,classes=classes)

    # 一对多管理器表修改 表移动
    # classes = Classes.objects.get(name='Python')
    # classes.article_set.add(Article.objects.get(title="test01"))

    # 多对多表数据添加
    # 给test01这篇文章添加两个标签
    # 第一步 先获取test01分类
    # article=Article.objects.get(title="test01")
    # article.label.create(name="test3321")
    # article.label.create(name="test3322")

    # 表数据删除
    # 移除test01标签
    # 第一步 先获取test01分类
    # article = Article.objects.get(title="test01")
    # article.label.remove(Label.objects.get(name='test3321'))
    # article.label.clear()

    # 恢复清空的表标签
    # article = Article.objects.get(title="test01")
    # article.label.add(Label.objects.get(name="test3321"))

    # 多表查询
    # 获取文章标题为test01的标签
    # 第一步 获取test01文章
    # article = Article.objects.get(title="test01")
    # label = Label.objects.get(name="test3321")
    # print(article.label.all())
    # print(label.article_set.all())

    # 获取id为1的分类文章的用户详情
    print(UserDetail.objects.filter(user__article__classes__id=19))
    # 获取Python下的所有文章
    print(Article.objects.filter(classes__name="Python"))
    return HttpResponse('成功')


class AddArticleView(View):
    # 添加登录校验的权限 用的是auth系统 不会在session表中查询
    @method_decorator(login_required)
    def get(self, request):
        form = ArticleForms()
        # username=request.session.get('username')
        username = request.user.username
        return render(request, 'demo/add_article.html', {'user': username, 'form': form})

    def post(self, request):
        # 绑定用户数据表单对象
        # 当需要使用表单时并且需要绑定文件数据 文件数据需要跟普通的表单数据分开处理
        # 文件数据并不会放到POST里 而是存放到file参数里面
        form = ArticleForms(request.POST, request.FILES)
        print(request.POST)
        print(request.FILES)
        username = request.user.username
        if form.is_valid():
            print('通过校验')
            title = form.cleaned_data.get('title')
            desc = form.cleaned_data.get('desc')
            content = form.cleaned_data.get('content')
            cover = form.cleaned_data.get('cover')
            classes = form.cleaned_data.get('classes')
            # 多对多的关系表 得到多个数据
            labels = form.cleaned_data.get('label')
            user = request.user
            print(title, desc, content, classes)
            print(cover, type(cover))
            print(labels, type(labels))
            print(user, type(user))
            # 保存图片时 图片名可能会出现重复
            # 为了图片名不重复 重写图片名 把时间戳跟图片名拼接
            file_name = f'{datetime.now().strftime("%Y%m%d%H%M%S")}_{cover.name}'
            # 图片地址
            with open(os.path.join(MEDIA_ROOT, file_name), 'wb') as fp:
                # 当图片文件过大时 通过chunks()方法将上传的文件数据分批次写入
                for data in cover.chunks():
                    fp.write(data)
            # 创建文件对象
            article = Article.objects.create(title=title, desc=desc, content=content, cover=file_name, user=user,
                                             classes=classes)
            # 多对多对已有数据的绑定
            for i in labels:
                article.label.add(i)
        # else:
        # print('没有通过校验')
        return render(request, 'demo/add_article.html', {'user': username, 'form': form})


class ArticleDetailView(View):
    # 查看一篇文章的详情内容 需要通过id(唯一)
    def get(self, request, id):
        try:
            article = Article.objects.get(id=id)
        except Article.DoesNotExist:
            return redirect('not_find')
        return render(request, 'demo/article_detail.html', context={'article': article, 'labels': article.label.all()})


# 创作中心页面 跟文章添加页面一样需要先登录
class ArticleUserView(View):
    # 添加权限校验
    @method_decorator(login_required)
    def get(self, request):
        # 查询到的该用户发布的所有文章信息
        articles = Article.objects.filter(user=request.user)
        # 自动做文章分页的操作
        # 每页只显示两篇文章 创建一个分页器对象
        pg = Paginator(articles, 2)
        try:
            pg_current = request.GET.get('page')  # 获取当前的页面
            # 获取当前的页面数据(对象)
            pages = pg.page(pg_current)
        # 如果页面不是一个整数 默认显示第一页
        except PageNotAnInteger:
            pages = pg.page(1)
        #     当page参数超过有效范围就显示最后一页
        except EmptyPage:
            pages = pg.page(pg.num_pages)
        return render(request, 'demo/user_article.html',
                      {"user": request.user.username, 'articles': articles, 'pages': pages})


class ArticleUpdateView(View):
    # 添加权限校验
    @method_decorator(login_required)
    # 要修改的那篇文章
    def get(self, request, id):
        try:
            article = Article.objects.get(id=id)
        except Article.DoesNotExist:
            return redirect('not_find')
        else:
            #     如果能够正常获取文章对象数据 就定义一个字典保存修改之前的文章数据
            data = {
                "title": article.title,
                "desc": article.desc,
                "content": article.content,
                "classes": article.classes,
                "label": article.label.all(),
            }
            form = ArticleForms(data)
        return render(request, 'demo/update_article.html', {"user": request.user.username, "form": form})

    def post(self, request, id):
        form = ArticleForms(request.POST, request.FILES)
        print(request.POST)
        print(request.FILES)
        username = request.user.username
        if form.is_valid():
            print('通过校验')
            title = form.cleaned_data.get('title')
            desc = form.cleaned_data.get('desc')
            content = form.cleaned_data.get('content')
            cover = form.cleaned_data.get('cover')
            classes = form.cleaned_data.get('classes')
            # 多对多的关系表 得到多个数据
            labels = form.cleaned_data.get('label')
            user = request.user
            print(title, desc, content, classes)
            print(cover, type(cover))
            print(labels, type(labels))
            print(user, type(user))
            # 保存图片时 图片名可能会出现重复
            # 为了图片名不重复 重写图片名 把时间戳跟图片名拼接
            file_name = f'{datetime.now().strftime("%Y%m%d%H%M%S")}_{cover.name}'
            # 图片地址
            with open(os.path.join(MEDIA_ROOT, file_name), 'wb') as fp:
                # 当图片文件过大时 通过chunks()方法将上传的文件数据分批次写入
                for data in cover.chunks():
                    fp.write(data)

            # 查询获取之前的文章信息
            articles = Article.objects.filter(id=id)
            # 删除之前保存的文章图片
            os.remove(os.path.join(MEDIA_ROOT, articles[0].cover))
            # 保存到数据库中
            # 创建文件对象
            articles.update(title=title, desc=desc, content=content, cover=file_name, user=user,
                            classes=classes)
            articles[0].label.clear()
            # 多对多对已有数据的绑定
            for i in labels:
                articles[0].label.add(i)
        # else:
        # print('没有通过校验')
        return redirect('ArticleUser')

class ArticleDelete(View):
    def get(self,request,id):
        try:
            article = Article.objects.get(id=id)
        except Article.DoesNotExist:
            return redirect('not_find')
        # 删除封面图
        os.remove(os.path.join(MEDIA_ROOT, article.cover))
        # 删除数据库里的文章数据
        article.delete()
        return redirect('ArticleUser')













